﻿#light

open System
open System.Collections.Generic
open System.Runtime.InteropServices
open System.Threading
open System.Threading.Tasks
open Dwarf.Managed

[<DllImport(@"CliTools.dll")>]
extern void start()

[<DllImport(@"CliTools.dll")>]
extern double finish()

[<DllImport(@"CliTools.dll")>]
extern void usage()

open MapReduceFSharpMethod

let initParallelization(mainContent : string, threadCount : int) : List<String> =
    let mutable currentDataArray = new List<String>()
    let mutable contentSize = (int) mainContent.Length
    let interval = (int) 1 + contentSize / threadCount
    let mutable leftBoard = (int) 0
    let mutable part = (int) 0
    for part = 0 to threadCount - 2 do
        let certainInterval = mainContent.IndexOf(' ', leftBoard + interval) + 1
        currentDataArray.Add(mainContent.Substring(leftBoard, certainInterval))
        leftBoard <- leftBoard + certainInterval        
        done
    currentDataArray.Add(mainContent.Substring(leftBoard))
    currentDataArray
    
let sumThreadResult(currentResultArray : List< Dictionary<string, int> >) : SortedDictionary<String, int> =
    let mutable stringTotal = currentResultArray.[0]
    for i = 1 to currentResultArray.Count - 1 do
        for pair in currentResultArray.[i] do
            if stringTotal.ContainsKey(pair.Key) then
                stringTotal.[pair.Key] <- pair.Value + stringTotal.[pair.Key]
            else
            stringTotal.Add(pair.Key, pair.Value)    
    new SortedDictionary<string, int>(stringTotal, StringComparer.Ordinal)
    
let parallelSolve (currentDataArray : List<String>, currentResultArray : List< Dictionary<string, int> >, threadCount : int)=
    let ParallelTask i =
        let contentDictionary = currentDataArray.[i] |> map |> reduce
        lock currentResultArray (fun () -> currentResultArray.Add(contentDictionary))
    Parallel.For(0, threadCount, new Action<int>(ParallelTask))
 
let solve(dwarfConfigurator : Configurator) : SortedDictionary<String, int> =
    dwarfConfigurator.WriteSettings()
    let mainContent = dwarfConfigurator.GetData()
    let threadCount = dwarfConfigurator.GetThreadCount()
    let currentDataArray = initParallelization(mainContent, threadCount)
    let currentResultArray = new List< Dictionary<string, int> >()
    parallelSolve(currentDataArray, currentResultArray, threadCount)
    sumThreadResult currentResultArray
 
let main() =
    let args = System.Environment.GetCommandLineArgs()
    let dwarfConfigurator = new Configurator(args)
    start()
    let mutable stringTotal = solve(dwarfConfigurator)   
    let time = finish()
    dwarfConfigurator.Close(time, stringTotal)  
 
main()
